<?php

/**
 * BaseContainerForm can be used as a wrapper for sfFormObject
 * This form provides methods for updating embed form related objects, and also saves them in database
 *
 * This form is an adaptation of sfFormObject class. Modifications where necesary to manage form objects
 * with a non form object
 *
 * @author Adrián Gallardo
 */
class BaseContainerForm extends sfForm {

    public function  bind(array $taintedValues = null, array $taintedFiles = null) {

        parent::bind($taintedValues, $taintedFiles);

        $this->bindEmbededForms($this->getEmbeddedForms(), $taintedValues, $taintedFiles);
    }

    private function bindEmbededForms($forms, $taintedValues, $taintedFiles){
        foreach($forms as $form){
            $values = isset($taintedValues[$form->getName()]) ? $taintedValues[$form->getName()] : array();
            $files  = isset($taintedFiles[$form->getName()])  ? $taintedFiles[$form->getName()]  : array();
            $embeded_forms = $form->getEmbeddedForms();

            if(!empty($embeded_forms)){
                $this->bindEmbededForms($embeded_forms, $taintedValues, $taintedFiles);
            } else {
                $form->bind($values, $files);
            }
        }
    }

    /**
     * Saves Embeded forms into database
     * @throws sfValidatorError If the form is not valid
     */
    public function save($con = null) {
        if (!$this->isValid()) {
            throw $this->getErrorSchema();
        }
        if ($con === null) {
            $con = $this->getConnection();
        }
        try {
            $con->beginTransaction();
            $this->doSave($con);
            $con->commit();
        } catch (Exception $e) {
            $con->rollBack();
            throw $e;
        }
    }

    /**
     * @return Doctrine_Connection
     * @see sfFormObject
     */
    public function getConnection() {
        return Doctrine_Manager::getInstance()->getCurrentConnection();
    }

    /**
     * Updates and saves the current object.
     * @param mixed $con An optional connection object
     */
    protected function doSave($con = null) {
        $this->updateObject();
        if ($this instanceof sfFormObject) {
            $this->getObject()->save($con);
        }

        // embedded forms
        $this->saveEmbeddedForms($con);
    }

    /**
     * Updates the values of the object with the cleaned up values.
     * @param  array $values An array of values
     * @return mixed The current updated object
     */
    public function updateObject($values = null) {
        if (null === $values) {
            $values = $this->values;
        }
        //$values = $this->processValues($values);

        $this->updateObjectEmbeddedForms($values);
    }

    /**
     * Updates the values of the objects in embedded forms.
     *
     * @param array $values An array of values
     * @param array $forms  An array of forms
     */
    public function updateObjectEmbeddedForms($values, $forms = null) {
        if (null === $forms) {
            $forms = $this->embeddedForms;
        }

        foreach ($forms as $name => $form) {
            if (!isset($values[$name]) || !is_array($values[$name])) {
                continue;
            }

            if ($form instanceof sfFormObject) {
                $form->updateObject($values[$name]);
            } else {
                $this->updateObjectEmbeddedForms($values[$name], $form->getEmbeddedForms());
            }
        }
    }

    /**
     * Saves embedded form objects.
     *
     * @param mixed $con   An optional connection object
     * @param array $forms An array of forms
     */
    public function saveEmbeddedForms($con = null, $forms = null) {

        if (null === $forms) {
            $forms = $this->embeddedForms;
        }

        foreach ($forms as $form) {
            if ($form instanceof sfFormObject) {
                $form->saveEmbeddedForms($con);
                $form->getObject()->save($con);
            } else {
                $this->saveEmbeddedForms($con, $form->getEmbeddedForms());
            }
        }
    }

}

?>
